/**
 * @file 	 xp_lpuart.c
 * @brief    当前驱动提供对指定的 LPUARTn 配置为通过 DMA + RingBuffer 发送和接收
 * @author 	 wenbo
 * @version  1.0
 * @date 	 2023-03-21
 *
 * @copyright Copyright (c) 2023  YGL
 *
 */

#include "xp_lpuart.h"
#include "string.h"
#include "board.h"
#include "MIMXRT1052.h"
#include "fsl_cache.h"
#include "fsl_lpuart_edma.h"
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
#include "fsl_dmamux.h"
#endif

#define LOGI    printf

#define LPUARTx_CLK_FREQ			BOARD_DebugConsoleSrcFreq()
#define DMAMUX_BASEADDR		DMAMUX
#define DMA_BASEADDR		DMA0

/**
 * @brief       定义使能的 LPUART
 */
#define ENABLE_LPUART1	0
#define ENABLE_LPUART2	0
#define ENABLE_LPUART3	0
#define ENABLE_LPUART4	0
#define ENABLE_LPUART6	1

#define MAX_RING_BUFFER_DEPTH			10

typedef struct
{
	uint8_t* pBuf;
	uint8_t head;
	uint8_t tail;
	uint8_t DEPTH;
	uint32_t SIZE;
	uint32_t msglen[MAX_RING_BUFFER_DEPTH];
} ringbuf_t;

typedef struct {
	LPUART_Type* base;
	IRQn_Type irqIndex;
	void (*LPUARTn_IRQHandler)(void);
	uint8_t dma_rx_ch;
	uint8_t dma_tx_ch;
	uint16_t dma_rx_request;
	uint16_t dma_tx_request;
	ringbuf_t rx_ringbuffer;
	ringbuf_t tx_ringbuffer;

	lpuart_edma_handle_t lpuartEdmaHandle;
	edma_handle_t lpuartTxEdmaHandle;
	edma_handle_t lpuartRxEdmaHandle;
	recv_irq_callback_t recv_irq_callback;

	bool isInit;
} lpuart_manage_t;


static void LPUARTx_IRQHandler(uint8_t port);
static void LPUART_UserCallback(LPUART_Type* base, lpuart_edma_handle_t* handle, status_t status, void* userData);
static void edma_recv_complite_callback(edma_handle_t* handle, void* param, bool transferDone, uint32_t tcds);
static lpuart_manage_t* get_handle_by_port(uint8_t port);
static bool is_edma_init = false;

// eDMA 内存定义在NONCACHEABLE区,且要32位对齐,因此当前驱动暂时使用静态缓存
#if (ENABLE_LPUART1) && (ENABLE_LPUART1 == 1)
#define LPUART1_RX_RB_SIZE 			128
#define LPUART1_RX_RB_DEPTH			3
#define LPUART1_TX_RB_SIZE 			128
#define LPUART1_TX_RB_DEPTH			3
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart1_dma_rx_mem[LPUART1_RX_RB_DEPTH][LPUART1_RX_RB_SIZE]) = { 0 };
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart1_dma_tx_mem[LPUART1_TX_RB_DEPTH][LPUART1_TX_RB_SIZE]) = { 0 };
void LPUART1_IRQHandler(void)
{
	LPUARTx_IRQHandler(1);
}
#endif

#if (ENABLE_LPUART2) && (ENABLE_LPUART2 == 1)
#define LPUART2_RX_RB_SIZE 			128
#define LPUART2_RX_RB_DEPTH			3
#define LPUART2_TX_RB_SIZE 			128
#define LPUART2_TX_RB_DEPTH			3
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart2_dma_rx_mem[LPUART2_RX_RB_DEPTH][LPUART2_RX_RB_SIZE]) = { 0 };
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart2_dma_tx_mem[LPUART2_TX_RB_DEPTH][LPUART2_TX_RB_SIZE]) = { 0 };
void LPUART2_IRQHandler(void)
{
	LPUARTx_IRQHandler(2);
}
#endif

#if (ENABLE_LPUART3) && (ENABLE_LPUART3 == 1)
#define LPUART3_RX_RB_SIZE 			128
#define LPUART3_RX_RB_DEPTH			3
#define LPUART3_TX_RB_SIZE 			128
#define LPUART3_TX_RB_DEPTH			3
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart3_dma_rx_mem[LPUART3_RX_RB_DEPTH][LPUART3_RX_RB_SIZE]) = { 0 };
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart3_dma_tx_mem[LPUART3_TX_RB_DEPTH][LPUART3_TX_RB_SIZE]) = { 0 };
void LPUART3_IRQHandler(void)
{
	LPUARTx_IRQHandler(3);
}
#endif

#if (ENABLE_LPUART4) && (ENABLE_LPUART4 == 1)
#define LPUART4_RX_RB_SIZE 			128
#define LPUART4_RX_RB_DEPTH			3
#define LPUART4_TX_RB_SIZE 			128
#define LPUART4_TX_RB_DEPTH			3
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart4_dma_rx_mem[LPUART4_RX_RB_DEPTH][LPUART4_RX_RB_SIZE]) = { 0 };
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart4_dma_tx_mem[LPUART4_TX_RB_DEPTH][LPUART4_TX_RB_SIZE]) = { 0 };
void LPUART4_IRQHandler(void)
{
	LPUARTx_IRQHandler(4);
}
#endif

#if (ENABLE_LPUART6) && (ENABLE_LPUART6 == 1)
#define LPUART6_RX_RB_SIZE 			1024
#define LPUART6_RX_RB_DEPTH			3
#define LPUART6_TX_RB_SIZE 			256
#define LPUART6_TX_RB_DEPTH			3
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart6_dma_rx_mem[LPUART6_RX_RB_DEPTH][LPUART6_RX_RB_SIZE]) = { 0 };
AT_NONCACHEABLE_SECTION_INIT(uint8_t lpuart6_dma_tx_mem[LPUART6_TX_RB_DEPTH][LPUART6_TX_RB_SIZE]) = { 0 };
void LPUART6_IRQHandler(void)
{
	LPUARTx_IRQHandler(6);
}
#endif


static lpuart_manage_t lpuart_manage_list[] = {
#if (ENABLE_LPUART1) && (ENABLE_LPUART1 == 1)
	{
		.base = LPUART1,
		.irqIndex = LPUART1_IRQn,
		.LPUARTn_IRQHandler = LPUART1_IRQHandler,
		.dma_rx_ch = 0,
		.dma_tx_ch = 16,
		.dma_rx_request = kDmaRequestMuxLPUART1Rx,
		.dma_tx_request = kDmaRequestMuxLPUART1Tx,
		.rx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart1_dma_rx_mem,
			.DEPTH = LPUART1_RX_RB_DEPTH,
			.SIZE = LPUART1_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		},
		.tx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart1_dma_rx_mem,
			.DEPTH = LPUART1_RX_RB_DEPTH,
			.SIZE = LPUART1_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		}
	},
#endif
#if (ENABLE_LPUART2) && (ENABLE_LPUART2 == 1)
	{
		.base = LPUART2,
		.irqIndex = LPUART2_IRQn,
		.LPUARTn_IRQHandler = LPUART2_IRQHandler,
		.dma_rx_ch = 1,
		.dma_tx_ch = 17,
		.dma_rx_request = kDmaRequestMuxLPUART2Rx,
		.dma_tx_request = kDmaRequestMuxLPUART2Tx,
		.rx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart2_dma_rx_mem,
			.DEPTH = LPUART2_RX_RB_DEPTH,
			.SIZE = LPUART2_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		},
		.tx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart2_dma_tx_mem,
			.DEPTH = LPUART2_TX_RB_DEPTH,
			.SIZE = LPUART2_TX_RB_SIZE,
			.head = 0,
			.tail = 0,
		}
	},
#endif
#if (ENABLE_LPUART3) && (ENABLE_LPUART3 == 1)
	{
		.base = LPUART3,
		.irqIndex = LPUART3_IRQn,
		.LPUARTn_IRQHandler = LPUART3_IRQHandler,
		.dma_rx_ch = 2,
		.dma_tx_ch = 18,
		.dma_rx_request = kDmaRequestMuxLPUART3Rx,
		.dma_tx_request = kDmaRequestMuxLPUART3Tx,
		.rx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart3_dma_rx_mem,
			.DEPTH = LPUART3_RX_RB_DEPTH,
			.SIZE = LPUART3_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		},
		.tx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart3_dma_tx_mem,
			.DEPTH = LPUART3_TX_RB_DEPTH,
			.SIZE = LPUART3_TX_RB_SIZE,
			.head = 0,
			.tail = 0,
		}
	},
#endif
#if (ENABLE_LPUART4) && (ENABLE_LPUART4 == 1)
	{
		.base = LPUART4,
		.irqIndex = LPUART4_IRQn,
		.LPUARTn_IRQHandler = LPUART4_IRQHandler,
		.dma_rx_ch = 3,
		.dma_tx_ch = 19,
		.dma_rx_request = kDmaRequestMuxLPUART4Rx,
		.dma_tx_request = kDmaRequestMuxLPUART4Tx,
		.rx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart4_dma_rx_mem,
			.DEPTH = LPUART4_RX_RB_DEPTH,
			.SIZE = LPUART4_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		},
		.tx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart4_dma_tx_mem,
			.DEPTH = LPUART4_TX_RB_DEPTH,
			.SIZE = LPUART4_TX_RB_SIZE,
			.head = 0,
			.tail = 0,
		}
	},
#endif
#if (ENABLE_LPUART6) && (ENABLE_LPUART6 == 1)
	{
		.base = LPUART6,
		.irqIndex = LPUART6_IRQn,
		.LPUARTn_IRQHandler = LPUART6_IRQHandler,
		.dma_rx_ch = 4,
		.dma_tx_ch = 20,
		.dma_rx_request = kDmaRequestMuxLPUART6Rx,
		.dma_tx_request = kDmaRequestMuxLPUART6Tx,
		.rx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart6_dma_rx_mem,
			.DEPTH = LPUART6_RX_RB_DEPTH,
			.SIZE = LPUART6_RX_RB_SIZE,
			.head = 0,
			.tail = 0,
		},
		.tx_ringbuffer = {
			.pBuf = (uint8_t*) lpuart6_dma_tx_mem,
			.DEPTH = LPUART6_TX_RB_DEPTH,
			.SIZE = LPUART6_TX_RB_SIZE,
			.head = 0,
			.tail = 0,
		}
	},
#endif
};

/**
 * @brief       LPUART eDMA 空闲回调(暂时用不到)
 * @param[in]	base                LPUART handle
 * @param[in]	handle              eDMA handle
 * @param[in]	status              Tx/Rx Idle state
 * @param[in]	userData            注册回调时设置的参数(这里是 lpuart_manage_t 句柄)
 */
static void LPUART_UserCallback(LPUART_Type* base, lpuart_edma_handle_t* handle, status_t status, void* userData)
{
	(void) base;
	(void) handle;
	(void) userData;

	if (kStatus_LPUART_TxIdle == status) {

	}

	if (kStatus_LPUART_RxIdle == status) {

	}
}
/**
 * @brief       eDMA 接收完成回调(eDMA 完成了配置的主循环次数的搬运)
 * @param[in]	handle              eDMA handle
 * @param[in]	param               注册回调时设置的参数(这里是 lpuart_manage_t 句柄)
 * @param[in]	transferDone		传输完成状态
 * @param[in]	tcds				分散聚集eDMA任务描述编号
 */
static void edma_recv_complite_callback(edma_handle_t* handle, void* param, bool transferDone, uint32_t tcds)
{
	lpuart_manage_t* p = (lpuart_manage_t*) param;
	assert(p);

	(void) tcds;
	(void) handle;

	if (transferDone) {
		// 进入此回调说明连续接收的数据量大于DMA一次主循环数(非正常情况)
		LPUART_TransferAbortReceiveEDMA(p->base, &p->lpuartEdmaHandle);

		/* 重新开始DMA接收传输 */
		lpuart_transfer_t receiveXfer;
		ringbuf_t* rb = &p->rx_ringbuffer;

		if (rb->tail != (rb->head + 1) % rb->DEPTH) {
			rb->head = (rb->head + 1) % rb->DEPTH;
		}

		receiveXfer.data = &rb->pBuf[rb->head * rb->SIZE];
		receiveXfer.dataSize = rb->SIZE;
		LPUART_ReceiveEDMA(p->base, &p->lpuartEdmaHandle, &receiveXfer);
	}
}
/**
 * @brief       通过端口编号获取 lpuart_manage_t 句柄
 * @param[in]	port                端口编号(1~n: LPUART1~LPUARTn)
 * @return      lpuart_manage_t*
 */
static lpuart_manage_t* get_handle_by_port(uint8_t port)
{
	if (port > 0) {
		for (size_t i = 0; i < sizeof(lpuart_manage_list) / sizeof(lpuart_manage_list[0]); i++) {
			uint32_t offset = ((uint32_t) lpuart_manage_list[i].base - (uint32_t) LPUART1);
			// 相邻 LPUART 基地址偏移为 0x4000 
			if (offset / 0x4000u == port - 1) {
				return &lpuart_manage_list[i];
			}
		}
	}
	return NULL;
}

void Init_LPUART(uint8_t port, uint32_t baudRate, uint8_t parity)
{
	Deinit_LPUART(port);
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	assert(parity < 3);

	lpuart_config_t lpuartConfig;
	uint8_t parityModeMap[] = { kLPUART_ParityDisabled, kLPUART_ParityEven, kLPUART_ParityOdd };

	LPUART_GetDefaultConfig(&lpuartConfig);

	lpuartConfig.rxIdleType = kLPUART_IdleTypeStopBit;
	lpuartConfig.rxIdleConfig = kLPUART_IdleCharacter4;
	lpuartConfig.baudRate_Bps = baudRate;
	lpuartConfig.parityMode = parityModeMap[parity];
	lpuartConfig.enableTx = true;
	lpuartConfig.enableRx = true;

	LPUART_Init(p->base, &lpuartConfig, LPUARTx_CLK_FREQ);

	edma_config_t config;

#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
	/* Init DMAMUX */
	DMAMUX_Init(DMAMUX_BASEADDR);
	/* Set channel for LPUART */
	DMAMUX_SetSource(DMAMUX_BASEADDR, p->dma_tx_ch, p->dma_tx_request);
	DMAMUX_SetSource(DMAMUX_BASEADDR, p->dma_rx_ch, p->dma_rx_request);
	DMAMUX_EnableChannel(DMAMUX_BASEADDR, p->dma_tx_ch);
	DMAMUX_EnableChannel(DMAMUX_BASEADDR, p->dma_rx_ch);
#endif

	if (!is_edma_init) {
		is_edma_init = true;
		EDMA_GetDefaultConfig(&config);
		EDMA_Init(DMA_BASEADDR, &config);
	}
	EDMA_CreateHandle(&p->lpuartTxEdmaHandle, DMA_BASEADDR, p->dma_tx_ch);
	EDMA_CreateHandle(&p->lpuartRxEdmaHandle, DMA_BASEADDR, p->dma_rx_ch);

	LPUART_TransferCreateHandleEDMA(p->base, &p->lpuartEdmaHandle, LPUART_UserCallback, p,
		&p->lpuartTxEdmaHandle, &p->lpuartRxEdmaHandle);

	EDMA_SetCallback(&p->lpuartRxEdmaHandle, edma_recv_complite_callback, p);
	// 准备接收
		lpuart_transfer_t receiveXfer;
		ringbuf_t* rb = &p->rx_ringbuffer;
		receiveXfer.data = &rb->pBuf[rb->head * rb->SIZE];
		receiveXfer.dataSize = rb->SIZE;
		LPUART_ReceiveEDMA(p->base, &p->lpuartEdmaHandle, &receiveXfer);
	p->isInit = true;
}

void Deinit_LPUART(uint8_t port)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);

	if (!p->isInit){
		return;
	}

	LPUART_DisableInterrupts(p->base, kLPUART_IdleLineInterruptEnable);
	DisableIRQ(p->irqIndex);

	LPUART_TransferAbortReceiveEDMA(p->base, &p->lpuartEdmaHandle);
	LPUART_TransferAbortSendEDMA(p->base, &p->lpuartEdmaHandle);

#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
	/* Init DMAMUX */
	DMAMUX_Deinit(DMAMUX_BASEADDR);
	/* Set channel for LPUART */
	DMAMUX_DisableChannel(DMAMUX_BASEADDR, p->dma_tx_ch);
	DMAMUX_DisableChannel(DMAMUX_BASEADDR, p->dma_rx_ch);
#endif

	LPUART_Deinit(p->base);
	p->isInit = false;
}

void LPUART_recv_enable(uint8_t port, bool enable)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	if (enable){
		LPUART_EnableInterrupts(p->base, kLPUART_IdleLineInterruptEnable);
		EnableIRQ(p->irqIndex);
	}else{
		LPUART_DisableInterrupts(p->base, kLPUART_IdleLineInterruptEnable);
		DisableIRQ(p->irqIndex);
		LPUART_TransferAbortReceiveEDMA(p->base, &p->lpuartEdmaHandle);
	}
}
/**
 * @brief       串口中断通用处理接口
 * @param[in]	port                端口编号(由硬件中断函数传入)
 */
static void LPUARTx_IRQHandler(uint8_t port)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	if(!p){
		return;
	}

	// alios底层将 std 等串口初始化时,打开了部分中断,但没有定义中断处理函数,会跳转到当前中断处理中,
	// 这里跳过没有通过 Init_LPUART() 接口初始化的串口中断.
	if (!p->isInit) {	
		if (2 == port){
			extern void LPUART2_DriverIRQHandler(void);
			LPUART2_DriverIRQHandler();
		}
		else if (4 == port){
			extern void LPUART4_DriverIRQHandler(void);
			LPUART4_DriverIRQHandler();
		}
		return;
	}

	uint32_t status = LPUART_GetStatusFlags(p->base);
	uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(p->base);
	ringbuf_t* rb = &p->rx_ringbuffer;

	if ((0U != ((uint32_t) kLPUART_IdleLineFlag & status)) &&
		(0U != ((uint32_t) kLPUART_IdleLineInterruptEnable & enabledInterrupts))) {
		(void) LPUART_ClearStatusFlags(p->base, kLPUART_IdleLineFlag);
		/* 刷新D-Cache，确保g_rxBuffer数据一致性 */
		DCACHE_CleanInvalidateByRange((uint32_t) rb->pBuf[rb->head * rb->SIZE], rb->SIZE);

		LPUART_TransferGetReceiveCountEDMA(p->base, &p->lpuartEdmaHandle, (uint32_t*) &rb->msglen[rb->head]);

		/* 数据读取处理慢的情况下选择覆盖上一帧 */
		if (rb->tail != (rb->head + 1) % rb->DEPTH) {
			rb->head = (rb->head + 1) % rb->DEPTH;
		}

		LPUART_TransferAbortReceiveEDMA(p->base, &p->lpuartEdmaHandle);

		/* 重新开始DMA接收传输 */
		lpuart_transfer_t receiveXfer;
		receiveXfer.data = &rb->pBuf[rb->head * rb->SIZE];
		receiveXfer.dataSize = rb->SIZE;
		LPUART_ReceiveEDMA(p->base, &p->lpuartEdmaHandle, &receiveXfer);

		/* 调用注册了的中断回调(注册的中断回调函数不可阻塞,不可使用非中断可用的操作系统API) */
		if (p->recv_irq_callback) {
			p->recv_irq_callback();
		}
	}
}
void register_recv_irq_callback(uint8_t port, recv_irq_callback_t cb)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	p->recv_irq_callback = cb;
}
bool push_to_tx_ringbuffer(uint8_t port, uint8_t const* pData, uint16_t size)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	ringbuf_t* rb = &p->tx_ringbuffer;

	if (!pData || size > rb->SIZE) {
		return false;
	}

	memcpy(&rb->pBuf[rb->head * rb->SIZE], (void*) pData, size);
	rb->msglen[rb->head] = size;

	/* 数据发送处理慢的情况下选择覆盖上一帧 */
	if (rb->tail != (rb->head + 1) % rb->DEPTH) {
		rb->head = (rb->head + 1) % rb->DEPTH;
	}
	return true;
}
bool pop_from_rx_ringbuffer(uint8_t port, uint8_t** pData, uint16_t* size)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	ringbuf_t* rb = &p->rx_ringbuffer;
	bool ret = false;

	if (!pData || !size) {
		return false;
	}
	/* 检测接收环形buffer是否有新数据 */
	if (rb->tail != rb->head) {
		*pData = &rb->pBuf[rb->tail * rb->SIZE];
		*size = rb->msglen[rb->tail];
		rb->tail = (rb->tail + 1) % rb->DEPTH;
		ret = true;
	}
	return ret;
}
bool flush_tx_ringbuffer(uint8_t port)
{
	lpuart_manage_t* p = get_handle_by_port(port);
	assert(p);
	ringbuf_t* rb = &p->tx_ringbuffer;

	bool ret = false;
	lpuart_transfer_t sendXfer;

	if (rb->tail != rb->head) {
		/* 这里对当前发送缓冲进一步判断其 size 是否为0, 否则将会assert */
		if (rb->msglen[rb->tail]) {
			sendXfer.data = &rb->pBuf[rb->tail * rb->SIZE];
			sendXfer.dataSize = rb->msglen[rb->tail];
			/* 发送忙时返回 busy */
			if (kStatus_Success == LPUART_SendEDMA(p->base, &p->lpuartEdmaHandle, &sendXfer)) {
				rb->tail = (rb->tail + 1) % rb->DEPTH;
				ret = true;
			}
		}
		else {
			rb->tail = (rb->tail + 1) % rb->DEPTH;
		}
	}else{
		ret = true;
	}
	return ret;
}




int LPUART_test(void)
{
#define test_port 6

	Init_LPUART(test_port, 115200, 0);

	lpuart_transfer_t sendXfer;

	while (1) {
		/* 接收处理 */
		/*********************************************************************************/
		uint8_t* pData;
		uint16_t size;
		if (pop_from_rx_ringbuffer(test_port, &pData, &size)) {

			LOGI("Recv %d, 0x%02X ... 0x%02X\r\n", size, pData[0], pData[size - 1]);
			push_to_tx_ringbuffer(test_port, pData, size);

			if (flush_tx_ringbuffer(test_port)) {
				LOGI("Send %d, 0x%02X ... 0x%02X\r\n", size, pData[0], pData[size - 1]);
			}
		}
	}
}

